﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Linq;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ProgramMain.Google;
using ProgramMain.Database;
using HashItem = System.Collections.Generic.KeyValuePair<double, int>;
using NearestSet = System.Collections.Generic.HashSet<System.Collections.Generic.KeyValuePair<double, int>>;

namespace ProgramMain.Layers
{
    public class NetLayer : GraphicLayer
    {
        public class FreeLine
        {
            public int Width { get; set; }
            public Color Color { get; set; }
            public CoordinateRectangle TunnelRect { get; set; }

        }

            
        private VertexTree RVertexTree = null;
        private CableTunnelTree RCableTunnelTree = null;

        private HashSet<int> _vertesLighted = new HashSet<int>();
        private HashSet<int> _cableTunnelLighted = new HashSet<int>();
        private HashSet<FreeLine> _freeLines = new HashSet<FreeLine>();
        private HashSet<Coordinate> _mapPoints = new HashSet<Coordinate>();

        public HashSet<int> CableTunnelLighted { get { return _cableTunnelLighted; } }

        public bool ShowTranzitVertex { get; set; }
        public bool IsDragDropVertex { get; set; }

        private readonly ReaderWriterLockSlim lockVR = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
        private readonly ReaderWriterLockSlim lockCTR = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

        protected class NetWorkerEvent : WorkerEvent
        {
            public NetWorkerEvent(WorkerEventType pEventType, EventPriorityType PriorityType)
                : base(pEventType, true, PriorityType)
            {
            }

            override public int CompareTo(object obj)
            {
                int res = base.CompareTo(obj);
                //if (res == 0)
                //{
                //    if (obj is NetWorkerEvent)
                //    {
                //        res = ((NetWorkerEvent)obj).VertexID.CompareTo(this.VertexID);
                //    }
                //    else
                //    {
                //        res = -1;
                //    }
                //}
                return res;
            }
        }

        private static Bitmap[] _Vertex = { null, null, null };
        public Bitmap Vertex
        {
            get
            {
                if (_Vertex[0] == null)
                {
                    _Vertex[0] = CreateCompatibleBitmap(Properties.Resources.vertex_8, PIFormat);
                    _Vertex[1] = CreateCompatibleBitmap(Properties.Resources.vertex_16, PIFormat);
                    _Vertex[2] = CreateCompatibleBitmap(Properties.Resources.vertex_24, PIFormat);
                }
                if (Level <= 14)
                    return _Vertex[0];
                else if (Level > 16)
                    return _Vertex[2];
                else 
                    return _Vertex[1];
            }
        }

        private static Bitmap[] _LightVertex = { null, null, null };
        private Bitmap LightVertex
        {
            get
            {
                if (_LightVertex[0] == null)
                {
                    _LightVertex[0] = CreateCompatibleBitmap(Properties.Resources.lightvertex_8, PIFormat);
                    _LightVertex[1] = CreateCompatibleBitmap(Properties.Resources.lightvertex_16, PIFormat);
                    _LightVertex[2] = CreateCompatibleBitmap(Properties.Resources.lightvertex_24, PIFormat);
                }
                if (Level <= 14)
                    return _LightVertex[0];
                else if (Level > 16)
                    return _LightVertex[2];
                else
                    return _LightVertex[1];
            }
        }

        private static Bitmap[] _TransitVertex = { null, null, null };
        public Bitmap TransitVertex
        {
            get
            {
                if (_TransitVertex[0] == null)
                {
                    _TransitVertex[0] = CreateCompatibleBitmap(Properties.Resources.transitvertex_8, PIFormat);
                    _TransitVertex[1] = CreateCompatibleBitmap(Properties.Resources.transitvertex_16, PIFormat);
                    _TransitVertex[2] = CreateCompatibleBitmap(Properties.Resources.transitvertex_24, PIFormat);
                }
                if (Level <= 14)
                    return _TransitVertex[0];
                else if (Level > 16)
                    return _TransitVertex[2];
                else
                    return _TransitVertex[1];
            }
        }

        private List<Bitmap> _CustomVertexList;
        private List<Bitmap> _LightCustomVertexList;

        #region CustomVertexIndexer class
        public class CustomVertexIndexer
        {
            private NetLayer _NetLayer;

            internal CustomVertexIndexer(NetLayer _NetLayer)
            {
                this._NetLayer = _NetLayer;
            }

            public Bitmap this[int index]
            {
                get
                {
                    index = (index - 1) * 3;

                    if (_NetLayer.Level <= 14)
                        index += 0;
                    else if (_NetLayer.Level > 16)
                        index += 2;
                    else
                        index += 1;

                    if (index >= _NetLayer._CustomVertexList.Count)
                        index = 0;

                    return _NetLayer._CustomVertexList[index];
                }
            }

            public int Length
            {
                get
                {
                    return _NetLayer._CustomVertexList.Count / 3;
                }
            }
        }

        public class LightCustomVertexIndexer
        {
            private NetLayer _NetLayer;

            internal LightCustomVertexIndexer(NetLayer _NetLayer)
            {
                this._NetLayer = _NetLayer;
            }

            public Bitmap this[int index]
            {
                get
                {
                    index = (index - 1) * 3;

                    if (_NetLayer.Level <= 14)
                        index += 0;
                    else if (_NetLayer.Level > 16)
                        index += 2;
                    else
                        index += 1;

                    if (index >= _NetLayer._LightCustomVertexList.Count)
                        index = 0;

                    return _NetLayer._LightCustomVertexList[index];
                }
            }

            public int Length
            {
                get
                {
                    return _NetLayer._LightCustomVertexList.Count / 3;
                }
            }
        }
        #endregion
        public readonly CustomVertexIndexer CustomVertex;
        public readonly LightCustomVertexIndexer LightCustomVertex; 
        
        public readonly static Size[] _HalfVertexSize = { new Size(4, 4), new Size(8, 8), new Size(12, 12) };
        public Size HalfVertexSize
        {
            get
            {
                if (Level <= 14)
                    return _HalfVertexSize[0];
                else if (Level > 16)
                    return _HalfVertexSize[2];
                else
                    return _HalfVertexSize[1];
            }
        }

        private static Size[] _HalfVertexSizetranzit = {new Size(2, 2), new Size(6, 6), new Size(8, 8)};
        public Size HalfVertexSizeTtanzit
        {
            get
            {
                if (Level <= 14)
                    return _HalfVertexSizetranzit[0];
                else if (Level > 16)
                    return _HalfVertexSizetranzit[2];
                else
                    return _HalfVertexSizetranzit[1];
            }
        }

        public double CoordinateTolerance { get; private set; }

        public NetLayer(int pWidth, int pHeight, Coordinate pCenterCoordinate, int pLevel, Control pDelegateControl, PixelFormat pPIFormat)
            : base(pWidth, pHeight, pCenterCoordinate, pLevel, pDelegateControl, pPIFormat)
        {
            CoordinateTolerance = 0;

            RVertexTree = new VertexTree();
            RCableTunnelTree = new CableTunnelTree();

            CustomVertex = new CustomVertexIndexer(this);
            LightCustomVertex = new LightCustomVertexIndexer(this);
            
            _CustomVertexList = new List<Bitmap>();
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.office_8, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.office_16, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.office_24, PIFormat));

            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_8, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_16, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_24, PIFormat));

            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_8, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_16, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_24, PIFormat));

            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_8, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_16, PIFormat));
            _CustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_24, PIFormat));

            _LightCustomVertexList = new List<Bitmap>();
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.lightoffice_8, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.lightoffice_16, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.lightoffice_24, PIFormat));

            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_8, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_16, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.house_24, PIFormat));

            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_8, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_16, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.turn_24, PIFormat));

            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_8, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_16, PIFormat));
            _LightCustomVertexList.Add(CreateCompatibleBitmap(Properties.Resources.CBVertes_24, PIFormat));
        }

        override protected void TranslateCoords()
        {
            base.TranslateCoords();

            // Определяем погрешность для попадания в объекты
            CoordinateTolerance = CenterCoordinate.Distance(
                CenterCoordinate + new GoogleCoordinate(HalfVertexSize.Width, 0/*HalfVertexSize.Height*/, Level));
        }

        protected override bool DispatchThreadEvents(WorkerEvent WorkerEvent)
        {
            bool res = base.DispatchThreadEvents(WorkerEvent);

            if (!res && WorkerEvent is NetWorkerEvent)
            {
                switch (WorkerEvent.EventType)
                {
                    case WorkerEventType.ReloadData:
                        {
                            ReadDBData();
                            return true;
                        }
                }
            }

            return res;
        }

        public void ReloadData()
        {
            PutWorkerThreadEvent(new NetWorkerEvent(WorkerEventType.ReloadData, EventPriorityType.Normal));
        }

        override protected void DrawLayer(Rectangle ClipRectangle)
        {
            try
            {
                SwapDrawBuffer();

                //рисовать все объекты на карте независимо от ClipRectangle, т.к. FillTransparent!
                FillTransparent();

                GoogleRectangle LocalScreenView = (GoogleRectangle)GoogleScreenView.Clone();

                RedrawCableTunnels(LocalScreenView);
                DrawFreeLine(LocalScreenView);
                RedrawVertexes(LocalScreenView);
                DrawMapPoint(LocalScreenView);
            }
            finally
            {
                SwapDrawBuffer();
            }
            FireIvalidateLayer(ClipRectangle);
        }

        private void ReadDBData()
        {
            ClearLighted();

            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Factory.StartNew(delegate { ReadVertexes(); }));
            tasks.Add(Task.Factory.StartNew(delegate { ReadCableTunnels(); }));
            Task.WaitAll(tasks.ToArray());
            
            Update(new Rectangle(0, 0, Width, Height));
        }

        private void ReadVertexes()
        {
            try
            {
                lockVR.EnterWriteLock();
                
                RVertexTree.LoadData();
            }
            finally
            {
                lockVR.ExitWriteLock();
            }
        }

        private void ReadCableTunnels()
        {
            try
            {
                lockCTR.EnterWriteLock();

                RCableTunnelTree.LoadData();
            }
            finally
            {
                lockCTR.ExitWriteLock();
            }
        }

        private bool RedrawVertexes(GoogleRectangle LocalScreenView)
        {
            try
            {
                lockVR.EnterReadLock();

                if (RVertexTree.ItemCount == 0) return true;

                HashSet<IGoogleTreeNode> res = RVertexTree.Query(LocalScreenView);

                if (ShowTranzitVertex)
                {
                    foreach (IGoogleTreeNode INode in res)
                    {
                        SimpleOpticNetDB.VertexesRow row = (SimpleOpticNetDB.VertexesRow) INode.Row;

                        if (row.IsImageIndexNull() && (row.IsIsEmptyNull() || !row.IsEmpty || ShowTranzitVertex))
                        {

                            Coordinate coordinate = new Coordinate(row.Longitude, row.Latitude);
                            Point point = coordinate.GetScreenPoint(LocalScreenView);

                            if (row.ID >= 0)
                            {
                                if (row.IsIsEmptyNull() || row.IsEmpty)
                                    DrawBitmap(TransitVertex, Point.Subtract(point, HalfVertexSize));
                            }
                            else
                            {
                                DrawBitmap(LightVertex, Point.Subtract(point, HalfVertexSize));
                            }

                            if (!row.IsCaptionNull() && row.Caption.Length > 0
                                && HalfVertexSizeTtanzit.Height > 6
                                && Properties.Settings.Default.ShowVertexNamesTranzit && row.IsEmpty
                                )
                            {
                                Size captionPozition = new Size(row.CaptionX, row.CaptionY);
                             //   DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, HalfVertexSizeTtanzit));
                                DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, captionPozition));
                            }

                        }
                    }
                }

                foreach (IGoogleTreeNode INode in res)
                {
                    SimpleOpticNetDB.VertexesRow row = (SimpleOpticNetDB.VertexesRow)INode.Row;

                    Coordinate coordinate = new Coordinate(row.Longitude, row.Latitude);
                    Point point = coordinate.GetScreenPoint(LocalScreenView);


                    if (row.IsIsEmptyNull() || !row.IsEmpty || ShowTranzitVertex)
                    {
                        if (!row.IsImageIndexNull())
                        {
                            if (_vertesLighted.Contains(row.ID))
                                DrawBitmap(LightCustomVertex[row.ImageIndex], Point.Subtract(point, HalfVertexSize));
                            else
                                DrawBitmap(CustomVertex[row.ImageIndex], Point.Subtract(point, HalfVertexSize));
                            if (!row.IsCaptionNull() && row.Caption.Length > 0
                            && HalfVertexSize.Height > 6 //&& !row.IsEmpty
                            && Properties.Settings.Default.ShowObjectName)
                            {
                                Size captionPozition = new Size(row.CaptionX, row.CaptionY);
                                //   DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, HalfVertexSizeTtanzit));
                                DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, captionPozition));
                            }
                        }
                        else
                        {
                            if (row.ID >= 0)
                            {
                                if (!row.IsEmpty)
                                    if (_vertesLighted.Contains(row.ID))
                                        DrawBitmap(LightVertex, Point.Subtract(point, HalfVertexSize));
                                    else
                                        DrawBitmap(Vertex, Point.Subtract(point, HalfVertexSize));
                                if (!row.IsCaptionNull() && row.Caption.Length > 0
                            && HalfVertexSize.Height > 6// && !row.IsEmpty
                            && Properties.Settings.Default.ShowVertexNames)
                                {
                                    Size captionPozition = new Size(row.CaptionX, row.CaptionY);
                                    //   DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, HalfVertexSizeTtanzit));
                                    DrawString(row.Caption, HalfVertexSizeTtanzit.Height, Point.Add(point, captionPozition));
                                }
                            }
                        }
                    }
                }

            }
            catch(Exception)
            {}
            finally
            {
                lockVR.ExitReadLock();
            }

            return true;
        }
        private void DrawFreeLine(GoogleRectangle LocalScreenView)
        {
            foreach (FreeLine item in _freeLines)
            {
                Rectangle rect = item.TunnelRect.GetScreenRect(LocalScreenView);
                DrawLine(rect, item.Width, item.Color);
            }
        }

        private void DrawMapPoint(GoogleRectangle LocalScreenView)
        {
            Bitmap bitmap = CreateCompatibleBitmap(Properties.Resources.Point_24, PIFormat);
            foreach(Coordinate item in _mapPoints)
            {
                Point point = item.GetScreenPoint(LocalScreenView);   
                DrawBitmap(bitmap, Point.Subtract(point, new Size(12, 24)));
            }
        }

        private bool RedrawCableTunnels(GoogleRectangle LocalScreenView)
        {
             try
            {
                lockCTR.EnterReadLock();

                if (RCableTunnelTree.ItemCount == 0) return true;

                int minCableTunnelSize = 6;// (HalfVertexSize.Width - 1) * 2;
                Size cableTunnelThickness = new Size(HalfVertexSize.Width / 2, HalfVertexSize.Height / 2);


                HashSet<IGoogleTreeNode> res = RCableTunnelTree.Query(LocalScreenView);
                foreach(IGoogleTreeNode INode in res)
                {
                    SimpleOpticNetDB.CableTunnelsRow row = (SimpleOpticNetDB.CableTunnelsRow)INode.Row;

                    CoordinateRectangle tunnelRect = new CoordinateRectangle(
                        row.Longitude1,
                        row.Latitude1,
                        row.Longitude2,
                        row.Latitude2);

                    Rectangle rect = tunnelRect.GetScreenRect(LocalScreenView);

                    if (rect.Width != 0 || rect.Height != 0)
                    {
                        int length;
                        if (ShowTranzitVertex)
                            length = (int)Math.Round(Math.Sqrt(Math.Pow(rect.Height, 2) + Math.Pow(rect.Width, 2)), 0);
                        else
                            length = minCableTunnelSize;

                        if (length >= minCableTunnelSize)
                        {
                            Color color = Color.Blue; //(row.ID > 0 && !CableTunnelLighted.Contains(row.ID)) ? Color.Blue : Color.Red;
                            if (row.ID < 1) color = Color.Red;
                            else if (_cableTunnelLighted.Contains(row.ID)) color = Color.Red;
                            else if (row.ID > 0 && row.CableTunnelTypeID == 1) color = Color.Blue;
                            else if (row.ID > 0 && row.CableTunnelTypeID == 2) color = Color.Indigo;
                            else if (row.ID > 0 && row.CableTunnelTypeID == 3) color = Color.DimGray;
                            else if (row.ID > 0 && row.CableTunnelTypeID == 5) color = Color.MidnightBlue;
                            DrawLine(rect, 2, color);

                            if ((!row.IsCaptionNull() && row.Caption.Length > 0
                                && HalfVertexSize.Height > 8
                                && Properties.Settings.Default.ShowCableTunnelNames) || IsDragDropVertex)
                            {
                                Coordinate coordinate = tunnelRect.LineMiddlePoint();
                                if (CoordinateScreenView.PointContains(coordinate) != InterseptResult.None)
                                {
                                    Point point = coordinate.GetScreenPoint(LocalScreenView);
                                    if (IsDragDropVertex) point += new Size(5, 5);
                                    string caption = (IsDragDropVertex&& !row.IsLocalAttributeNull() && row.LocalAttribute ==1)? 
                                        Math.Round(tunnelRect.LeftTop.Distance(tunnelRect.RightBottom),2).ToString() 
                                        :(!row.IsCaptionNull() && row.Caption.Length > 0)? row.Caption:"";

                                    DrawString(caption, HalfVertexSize.Height, Point.Add(point, cableTunnelThickness));
                                }
                            }
                        }
                    }
                }
            }
                catch
            {}
            finally
            {
                lockCTR.ExitReadLock();
            }
            return true;
        }

        public void MergeData(SimpleOpticNetDB.VertexesDataTable vertexes)
        {
            try
            {
                lockVR.EnterWriteLock();

                RVertexTree.MergeData(vertexes);
            }
            finally
            {
                lockVR.ExitWriteLock();
            }
            Update(new Rectangle(0, 0, Width, Height));
        }

        public void RemoveVertex(int ObjectID)
        {
            bool bUpdate = false;
            try
            {
                lockVR.EnterWriteLock();

                if (RVertexTree.ItemCount == 0) return;

                bUpdate = RVertexTree.RemoveVertex(ObjectID);

                RemoveVertesLighted(ObjectID);
            }
            finally
            {
                lockVR.ExitWriteLock();
            }
            if (bUpdate)
                Update(new Rectangle(0, 0, Width, Height));
        }

        public void MergeData(SimpleOpticNetDB.CableTunnelsDataTable cableTunnels)
        {
            try
            {
                lockCTR.EnterWriteLock();

                RCableTunnelTree.MergeData(cableTunnels);
            }
            finally
            {
                lockCTR.ExitWriteLock();
            }
            Update(new Rectangle(0, 0, Width, Height));
        }

        public void RemoveCableTunnel(int ObjectID)
        {
            bool bUpdate = false;
            try
            {
                lockCTR.EnterWriteLock();
                
                if (RCableTunnelTree.ItemCount == 0) return;

                bUpdate = RCableTunnelTree.RemoveCableTunnel(ObjectID);
            }
            finally
            {
                lockCTR.ExitWriteLock();
            }
            if (bUpdate)
                Update(new Rectangle(0, 0, Width, Height));
        }

        public HashItem[] FindNearestVertex(Coordinate pt)
        {
            NearestSet list = new NearestSet();
            try
            {
                lockVR.EnterReadLock();

                if (RVertexTree.ItemCount == 0)
                    return list.ToArray();

                HashSet<IGoogleTreeNode> res = RVertexTree.Distance(pt, CoordinateTolerance);
                foreach (IGoogleTreeNode INode in res)
                {
                    SimpleOpticNetDB.VertexesRow row = (SimpleOpticNetDB.VertexesRow)INode.Row;

                    Coordinate coordinate = new Coordinate(row.Longitude, row.Latitude);

                    double distance = coordinate.Distance(pt);
                    list.Add(new HashItem(distance, row.ID));
                }
            }
            finally
            {
                lockVR.ExitReadLock();
            }
            return list.OrderBy(item => item.Key).ToArray();
        }

        public HashItem[] FindNearestCableTunnel(Coordinate pt)
        {
            NearestSet list = new NearestSet();
            try
            {
                lockCTR.EnterReadLock();

                if (RCableTunnelTree.ItemCount == 0)
                    return list.ToArray();

                HashSet<IGoogleTreeNode> res = RCableTunnelTree.Distance(pt, CoordinateTolerance);
                foreach (IGoogleTreeNode INode in res)
                {
                    SimpleOpticNetDB.CableTunnelsRow row = (SimpleOpticNetDB.CableTunnelsRow)INode.Row;

                    CoordinateRectangle tunnelRect = new CoordinateRectangle(
                        row.Longitude1,
                        row.Latitude1,
                        row.Longitude2,
                        row.Latitude2);

                    double distance = tunnelRect.LineDistance(pt);
                    list.Add(new HashItem(distance, row.ID));
                }
            }
            finally
            {
                lockCTR.ExitReadLock();
            }
            
            return list.OrderBy(item => item.Key).ToArray();
        }

        public SimpleOpticNetDB.VertexesRow FindVertex(int ObjectID)
        {
            try
            {
                lockVR.EnterReadLock();
                
                return RVertexTree.FindVertex(ObjectID);
            }
            finally
            {
                lockVR.ExitReadLock();
            }
        }

        public void AddVertesLighted(int vertexID)
        {
            if (!_vertesLighted.Contains(vertexID)) _vertesLighted.Add(vertexID);
            Update();
        }

        public void AddMapPoint(Coordinate coordinate)
        {
            if (!_mapPoints.Contains(coordinate)) _mapPoints.Add(coordinate);
            Update();
        }
        public void AddFreeLine(FreeLine freeLine)
        {
            if (!_freeLines.Contains(freeLine)) _freeLines.Add(freeLine);
            Update();
        }
        public void RemoveVertesLighted(int vertexID)
        {
            if (!_vertesLighted.Contains(vertexID)) _vertesLighted.Remove(vertexID);
            Update();
        }

        public void AddCableTunnelLighted(int cableTunnelID)
        {
            if (!_cableTunnelLighted.Contains(cableTunnelID)) _cableTunnelLighted.Add(cableTunnelID);
            Update();
        }

        public void RemoveCableTunnelLighted(int cableTunnelID)
        {
            if (_cableTunnelLighted.Contains(cableTunnelID)) _cableTunnelLighted.Remove(cableTunnelID);
            Update();
        }

        public void ClearLighted()
        {
            _vertesLighted.Clear();
            _cableTunnelLighted.Clear();
            _freeLines.Clear();
            _mapPoints.Clear();
            Update();
        }
    }
}
